/**
 * 
 */
package com.googlecode.dynargs.extractor;

import java.lang.reflect.Field;
import java.util.List;

import com.googlecode.dynargs.model.constraints.Constraint;
import com.googlecode.dynargs.model.type.ObjectField;
import com.googlecode.dynargs.model.type.ObjectType;
import com.googlecode.dynargs.model.type.Type;

/**
 * @author "Federico De Faveri defaveri@gmail.com"
 *
 */
public class ReflectionExtractor implements TypeExtractor<ObjectType> {

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean canExtract(TypeToken clazz) {
		return true;
	}

	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public ObjectType extract(ModelExtractor modelExtractor, TypeToken type) {
		
		Class<?> clazz = type.getRawType();
		
		String id = clazz.getName();
		
		modelExtractor.getLogger().println(id);
		
		ObjectType object = new ObjectType(id);

		for (Field field:clazz.getDeclaredFields()) {
			ObjectField objectField = getField(modelExtractor, field);
			object.addField(objectField);
		}
		
		return object;	
	}
	
	protected ObjectField getField(ModelExtractor modelExtractor, Field field)
	{
		modelExtractor.getLogger().inc();

		String name = field.getName();
		
		Class<?> fieldClass = field.getType();
		
		java.lang.reflect.Type genericType = field.getGenericType();		
		
		TypeToken typeToken = new TypeToken(fieldClass, genericType);

		String id = fieldClass.getName();
		modelExtractor.getLogger().println(id+" "+name);

		Type type = modelExtractor.getFromTypesCache(id);
		if (type==null) type = modelExtractor.extract(typeToken);

		ObjectField objectField = new ObjectField(name, type);
		com.googlecode.dynargs.model.annotation.Field fieldAnnotation = field.getAnnotation(com.googlecode.dynargs.model.annotation.Field.class);
		if (fieldAnnotation!=null) {
			objectField.setLabel(fieldAnnotation.label());
			objectField.setDescription(fieldAnnotation.description());
		}
		
		List<Constraint> constraints = modelExtractor.extractConstraints(field);
		objectField.setConstraints(constraints);
		
		modelExtractor.getLogger().dec();
		return objectField;
	}
}
